#  This file is part of -_-.
#
#    -_- is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    -_- is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with -_-.  If not, see <http://www.gnu.org/licenses/>.
#
#    Copyright 2012-2013 Oliver Katz

# DIRECTORIES (I know PWD is initialized by default, but there are cases when it doesn't work as expected)
PWD=$(shell pwd)
SRC=$(PWD)
COMMON=$(SRC)/common
COMMON_TYPES=$(COMMON)/types
BUS=$(SRC)/bus
VM=$(SRC)/vm
OPAL=$(SRC)/opal
OPAL_STD=$(OPAL)/std
OPAL_CODESERVER=$(OPAL)/codeserver
VISUAL=$(SRC)/visual
ARCH=$(SRC)/arch
ARCH_MODULES=$(ARCH)/modules
EXTRA=$(SRC)/extra
EXTRA_BUILDABLE=$(EXTRA)/buildable
DOC=$(SRC)/doc
DOC_REFERENCE=$(DOC)/reference

# DEPENDENCIES #
PACKAGES=directfb
INCLUDES=-I. -I/usr/include/llvm -I/usr/include/llvm/Analysis -I/usr/include/llvm/ExecutionEngine -I/usr/include/llvm/Support -ILU -I$(SRC) -I$(COMMON) -I$(BUS) -I$(VM) -I$(OPAL) -I$(OPAL_CODESERVER) -I$(VISUAL) -I$(ARCH) -I$(ARCH_MODULES) -I$(EXTRA) -I$(EXTRA_BUILDABLE) -I/usr/include
LIBPATH=-L$(SRC)
LIBS=-ldl -lreadline -lstdc++ -lgtest

# FLAGS AND COMMANDS #
#-DZ_ENABLE_STACKTRACES - add stacktraces to warning output (warning: rather slow)
CC=gcc
CXX=g++

OPT=-O2
DBG=-g
EXT_CFLAGS=
COMMON_CFLAGS=$(DBG) $(OPT) -fPIC -D__YEAR__=$(shell date +%Y) $(EXT_CFLAGS)
CFLAGS=$(COMMON_CFLAGS) --std=c99 $(shell pkg-config --cflags $(PACKAGES)) $(INCLUDES)
CXXFLAGS=$(COMMON_CFLAGS) -std=c++11 $(shell pkg-config --cflags $(PACKAGES)) $(INCLUDES) $(shell llvm-config --cppflags) -DNDEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fomit-frame-pointer

COMMON_LDFLAGS=-l-_-
LDFLAGS=$(COMMON_LDFLAGS) $(shell pkg-config --libs $(PACKAGES)) $(LIBPATH) $(LIBS)
LDXXFLAGS=$(COMMON_LDFLAGS) $(shell pkg-config --libs $(PACKAGES)) $(LIBPATH) $(LIBS) $(shell llvm-config --ldflags --libs core jit native)
SONAME=-shared -Wl,-soname,

RM=rm
RMFLAGS=-f --
AR=ar
ARFLAGS=rcs

# OBJECT LISTS #
COMMON_OBJ=$(COMMON)/debug.o $(COMMON)/data.o $(COMMON)/fio.o $(COMMON)/msg.o $(COMMON)/args.o $(COMMON)/list.o $(COMMON)/pluginloader.o
COMMON_OBJ_TEST=$(COMMON)/test_plugin.o $(COMMON)/test_plugin_loader.o
COMMON_TYPES_OBJ=$(COMMON_TYPES)/vector.o $(COMMON_TYPES)/string.o $(COMMON_TYPES)/assoc.o $(COMMON_TYPES)/pair.o
COMMON_TYPES_OBJ_TEST=
BUS_OBJ=$(BUS)/ipc.o $(BUS)/share.o $(BUS)/bus.o
BUS_OBJ_TEST=$(BUS)/test_bus_client.o $(BUS)/test_share_client.o $(BUS)/test_share_server.o
VM_OBJ=$(VM)/vm.o
VM_OBJ_TEST=
OPAL_OBJ=$(OPAL)/error.o $(OPAL)/lexer.o $(OPAL)/parser.o $(OPAL)/macro.o
OPAL_OBJ_TEST=$(OPAL)/test_parsing.o
OPAL_STD_OBJ=$(OPAL_STD)/subprocess.o $(OPAL_STD)/io.o
OPAL_STD_OBJ_TEST=
OPAL_CODESERVER_OBJ=$(OPAL_CODESERVER)/codeserver.o
OPAL_CODESERVER_OBJ_TEST=$(OPAL_CODESERVER)/test_codeserver.o
VISUAL_OBJ=$(VISUAL)/visual.o $(VISUAL)/pane.o $(VISUAL)/script.o $(VISUAL)/allocator.o
VISUAL_OBJ_TEST=$(VISUAL)/test_visual_client.o
ARCH_OBJ=$(ARCH)/module.o $(ARCH)/arch.o $(ARCH)/arch_c_compat.o
ARCH_OBJ_TEST=
ARCH_MODULES_OBJ=$(ARCH_MODULES)/mod_argbuf.o $(ARCH_MODULES)/mod_bus.o $(ARCH_MODULES)/mod_log.o $(ARCH_MODULES)/mod_share_client.o $(ARCH_MODULES)/mod_share_server.o $(ARCH_MODULES)/mod_codeserver.o $(ARCH_MODULES)/mod_ipc_client.o $(ARCH_MODULES)/mod_ipc_server.o $(ARCH_MODULES)/mod_visual_script.o
ARCH_MODULES_OBJ_TEST=
EXTRA_DISPLAY_ENGINES_SHINY_OBJ=
EXTRA_DISPLAY_ENGINES_SHINY_OBJ_TEST=
EXTRA_BUILDABLE_OBJ=
EXTRA_BUILDABLE_OBJ_TEST=
OBJ=$(COMMON_OBJ) $(BUS_OBJ) $(COMMON_TYPES_OBJ) $(VM_OBJ) $(OPAL_OBJ) $(OPAL_STD_OBJ) $(OPAL_CODESERVER_OBJ) $(ARCH_OBJ) $(VISUAL_OBJ) $(ARCH_MODULES_OBJ) $(EXTRA_BUILDABLE_OBJ)
OBJ_TEST=$(COMMON_OBJ_TEST) $(COMMON_TYPES_OBJ_TEST) $(BUS_OBJ_TEST) $(VM_OBJ_TEST) $(OPAL_OBJ_TEST) $(OPAL_STD_OBJ_TEST) $(OPAL_CODESERVER_OBJ_TEST) $(VISUAL_OBJ_TEST) $(ARCH_OBJ_TEST) $(ARCH_MODULES_OBJ_TEST) $(EXTRA_BUILDABLE_OBJ_TEST)

# TARGETS #
BUILD_TARGETS=$(SRC)/lib-_-.a $(BUS)/-_-bus $(EXTRA_BUILDABLE)/-_-buildable $(VISUAL)/-_-visual
TEST_TARGETS=$(OBJ_TEST) $(COMMON)/libtest_plugin.so $(COMMON)/test_plugin_loader.bin $(COMMON)/test_bus_client.bin $(COMMON)/test_share_client.bin $(COMMON)/test_share_server.bin $(OPAL)/test_parsing.bin $(OPAL_CODESERVER)/test_codeserver.bin $(VISUAL)/test_visual_client.bin

all : build

%.o : %.c
	$(CC) $(CFLAGS) -c $< -o $@

%.o : %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

$(BUS)/-_-bus : $(BUS)/main.o $(BUS_OBJ) $(COMMON_OBJ)
	$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)

$(EXTRA_BUILDABLE)/-_-buildable : $(EXTRA_BUILDABLE)/main.o $(OBJ)
	$(CXX) $(CXXFLAGS) $< -o $@ $(LDXXFLAGS)

$(VISUAL)/-_-visual : $(VISUAL)/main.o $(OBJ)
	$(CXX) $(CXXFLAGS) $< -o $@ $(LDXXFLAGS)

$(SRC)/lib-_-.a : $(OBJ)
	$(AR) $(ARFLAGS) $@ $^

build : $(BUILD_TARGETS)

$(COMMON)/libtest_plugin.so : $(COMMON_OBJ) $(COMMON_OBJ_TEST)
	$(CC) $(CFLAGS) $(COMMON)/test_plugin.o -o $(COMMON)/libtest_plugin.so $(SONAME)libtest_plugin.so $(LDFLAGS)

$(COMMON)/test_plugin_loader.bin : $(COMMON_OBJ) $(COMMON_OBJ_TEST)
	$(CXX) $(CXXFLAGS) $(COMMON)/test_plugin_loader.o -o $(COMMON)/test_plugin_loader.bin $(LDXXFLAGS)

$(COMMON)/test_bus_client.bin : $(COMMON_OBJ) $(COMMON_OBJ_TEST)
	$(CXX) $(CXXFLAGS) $(BUS)/test_bus_client.o -o $(COMMON)/test_bus_client.bin $(LDXXFLAGS)

$(COMMON)/test_share_client.bin : $(COMMON_OBJ) $(COMMON_OBJ_TEST)
	$(CXX) $(CXXFLAGS) $(BUS)/test_share_client.o -o $(COMMON)/test_share_client.bin $(LDXXFLAGS)

$(COMMON)/test_share_server.bin : $(COMMON_OBJ) $(COMMON_OBJ_TEST)
	$(CXX) $(CXXFLAGS) $(BUS)/test_share_server.o -o $(COMMON)/test_share_server.bin $(LDXXFLAGS)

$(OPAL)/test_parsing.bin : $(OPAL_OBJ) $(OPAL_OBJ_TEST) $(COMMON_OBJ)
	$(CXX) $(CXXFLAGS) $(OPAL)/test_parsing.o -o $(OPAL)/test_parsing.bin $(LDXXFLAGS)

$(OPAL_CODESERVER)/test_codeserver.bin : $(OPAL_OBJ) $(OPAL_OBJ_TEST) $(OPAL_CODESERVER_OBJ) $(OPAL_CODESERVER_OBJ_TEST) $(VM_OBJ)
	$(CXX) $(CXXFLAGS) $(OPAL_CODESERVER)/test_codeserver.o -o $(OPAL_CODESERVER)/test_codeserver.bin $(LDXXFLAGS)

$(VISUAL)/test_visual_client.bin : $(OBJ) $(VISUAL_OBJ_TEST)
	$(CXX) $(CXXFLAGS) $(VISUAL)/test_visual_client.o -o $(VISUAL)/test_visual_client.bin $(LDXXFLAGS)

test : build $(TEST_TARGETS)

clean : 
	$(RM) $(RMFLAGS) $(shell echo *.a *.o */*.a */*.o */*/*.a */*/*.o */*/*/*.a */*/*/*.o) $(BUILD_TARGETS) $(TEST_TARGETS)

documentation :
	$(DOC)/-_-doc --generate-header-documentation $(SRC) $(DOC_REFERENCE)/overview.html > $(DOC_REFERENCE)/index.html
	$(DOC)/-_-doc --generate-tutorial-documentation $(DOC_REFERENCE)/tutorial.txt > $(DOC_REFERENCE)/tutorial.html
